﻿/*
Copyright (c) Microsoft Corporation

All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.  You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0   

THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.  

See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. 
*/

//-------------------------------------------------- //
/*
particlemanager.js - 

*/
//---------------------------------------------------//

(function (window) {
    "use strict";
    var ParticleManager = function(canvasID){
        this.isLoaded = false;
        this.maxNumofParticles = 20;
        this.particle_data = {};

        this.canvaselement = null; //particles are drawn on a seperate canvas from the rest of the game.
        this.canvascontext = null;

        this.scaling = {x: 1, y: 1};
        this.spawntimer = 10;

        this.init = function (canvasID) {

            this.canvaselement = document.getElementById(canvasID);
            var html_elm = document.getElementsByTagName('html')[0];
            this.canvaselement.setAttribute('height', html_elm.clientHeight);
            this.canvaselement.setAttribute('width', html_elm.clientWidth);
            this.canvascontext = this.canvaselement.getContext('2d');


            this.particleArray = [];
            this.isDead = [];
            this.isActive = [];

            for (var i = 0; i < this.maxNumofParticles; i++) {
                this.particleArray[i] = new Particle(this);
                this.isDead[i] = i;
            }

            //setup the particle data
            this.particle_data['snowflake'] = { frames: null, spritesheet: null };
            this.particle_data['snowflake'].frames = [new game.Frame(0, 0, 74, 75)];
            this.particle_data['snowflake'].spritesheet = this.createspritesheet('media/snowflake.png');    
        };

        this.createspritesheet = function (path) {
            var that = this;
            //create IMG element and load image
            var img = new Image();
            img.src = path;

            img.onerror = function () {
                console.log("IMG ERROR");
            };
            img.onload = function () {
                that.isLoaded = true;
            };

            return img;
        };

        this.spawnGroup = function (pos, spread, vel, velvariance, rotation, rotvariance, num, type, isAlive, callerID, isRandom) {
            if (isRandom === undefined || isRandom === null) {
                isRandom = false;
            }
            //number of particles, pos, type
            if (this.isDead.length < num) {
                //cap number of particles based on maxParticles possible
                num = this.isDead.length;
            }
            type = type.toLowerCase();
            var particlePos = { x: 0, y: 0 };
            var particleVel = { x: 0, y: 0 };

            var frame = 0;
            var particleType = null;

            if (this.particle_data[type] !== undefined) {
                particleType = this.particle_data[type];
            }
            else {
                console.log("INVALID PARTICLE TYPE: " + type + " | CALLER: " + callerID);
                return;
            }

            if (isRandom === false) {
                num = Math.min(num, particleType.frames.length); // cap frames to length if not random
            }

            for (var i = 0; i < num; i++) {

                var frame = 0;
                if (isRandom === true) {
                    frame = Math.round(Math.random() * (particleType.frames.length - 1)); //Randomly get frame
                }
                else {
                    if (i >= particleType.frames.length) {
                        //console.log("ERROR: Particle type " + type + " does not have a frame " + i);
                        return;
                    }
                    frame = i;
                    frame = Math.min(particleType.frames.length, frame); //cap at max frame
                }

                particlePos.x = pos.x + Math.random() * spread.x; //Adding in spawn variance
                particlePos.y = pos.y + Math.random() * spread.y;

                particleVel.x = vel.x + (Math.random() * (-1 * this.getRandBinary())) * velvariance; //Adding in spawn vel variance
                particleVel.y = vel.y + (Math.random() * (-1 * this.getRandBinary())) * velvariance;

                if (this.isDead.length > 0) {
                    this.particleArray[this.isDead.pop()].spawn({ x: particlePos.x, y: particlePos.y }, { x: particleVel.x, y: particleVel.y }, rotation + Math.random() * (-1 * this.getRandBinary()) * rotvariance,
                                                 type, isAlive, callerID, particleType.spritesheet, particleType.frames[frame]);
                }
            }

        };

        this.update = function () {
            this.spawntimer--;
            if (this.spawntimer < 0) {
                this.spawnGroup({ x: Math.random() * this.canvaselement.width, y: -100 }, { x: 0, y: 0 }, { x: 0, y: 0 },
                            0, 5, 5, 1, 'snowflake', true, 0, true);
                this.spawntimer = Math.random() * 20;
            }
            this.scalecheck();

            for (var i = 0; i < this.isActive.length; i++) {
                if (this.isActive[i].update()) {
                    //particle is dead
                    //push index to dead array
                    this.isDead.push(this.particleArray.indexOf(this.isActive[i]));
                    this.isActive[i].deactivate();
                }
            }
        };

        this.draw = function () {
            var tempContext = game.system.canvascontext; //switch context over to particle canvas
            game.system.canvascontext = this.canvascontext;
            this.canvascontext.save();
            this.canvascontext.setTransform(1, 0, 0, 1, 0, 0); //reset transform to normal
            this.canvascontext.clearRect(0, 0, this.canvaselement.width, this.canvaselement.height);
            this.canvascontext.restore();
            for (var i = 0; i < this.isActive.length; i++) {
                this.isActive[i].draw();
            }
            game.system.canvascontext = tempContext;
        };

        this.scalecheck = function () {
            //checks if scale has changed, and if it has updates particle canvas scaling
            var newscaleX = 768 /GLOBAL_APPWIDTH ;
            newscaleX = parseFloat(newscaleX.toFixed(5));
            var newscaleY = 1366 /GLOBAL_APPHEIGHT;
            newscaleY = parseFloat(newscaleY.toFixed(5));
            if (newscaleX !== this.scaling.x || newscaleY !== this.scaling.y) {
                //scaling has changed update canvas scale
                this.canvascontext.setTransform(1, 0, 0, 1, 0, 0); //reset transform to normal
                this.canvascontext.scale(this.scaling.x, this.scaling.y); //use canvas scaling to preserve proper ratio
                this.scaling.x = newscaleX;
                this.scaling.y = newscaleY;
            }
        };

        this.getRandBinary = function () {
            return Math.floor(Math.random() * 2);
        };

        this.activate = function (callerID) {
            var i;
            for (i = this.maxNumofParticles - 1; i >= 0; i--) {
                if (this.particleArray[i].ownerID == callerID) { //find first particle then break out of search
                    break;
                }
            }

            while (this.particleArray[i].ownerID == callerID && i >= 0) { //All particles of a caller should be next to each other
                this.particleArray[i].activate();
                i--;
            }
        };

        this.updategravity = function (callerID, gravity) {
            var i;
            for (i = this.maxNumofParticles - 1; i >= 0; i--) {
                if (this.particleArray[i].ownerID == callerID) { //find first particle then break out of search
                    break;
                }
            }

            while (this.particleArray[i].ownerID == callerID && i >= 0) { //All particles of a caller should be next to each other
                this.particleArray[i].gravity = gravity;
                i--;
            }
        };

        this.set_isalive = function (callerID, isAlive) {
            var i;
            for (i = this.maxNumofParticles - 1; i >= 0; i--) { //start at end because particles are more likely to be at that end
                if (this.particleArray[i].ownerID == callerID) { //find first particle then break out of search
                    break;
                }
            }
        };

        this.init(canvasID);
    };

    var Particle = function(manager){
        this.manager = null;

        this.size =  { width: 0, height: 0 };
        this.pos = { x: 0, y: 0 };
        this.last = { x: 0, y: 0, angle: 0 };
        this.interpolate_diff = { x: 0, y: 0, angle: 0 };

        this.gravity = 500;
        this.vel = { x: 0, y: 0 };
        this.accel = { x: 0, y: 0 };
        this.rotationspeed = 0;
        this.angle = 0;
        this.lifetime = 300;
        this.isAlive = false;
        this.isActive = false;
        this.ownerID = 0;

        this.init = function (manager) {
            //only called once on game load to initialize data
            this.manager = manager; // saves pointer to the manager for referencing
            this.particle_canvas = document.getElementById('particle_canvas');
            this.kill_x = this.particle_canvas.width;
            this.kill_y = this.particle_canvas.height;
        };

        this.spawn = function (pos, vel, rotation, grouptype, isAlive, ID, img_data, frame) {
            this.spritesheet = img_data;

            this.baseframe = frame;
            this.ownerID = ID;
            this.pos = pos;
            this.last.x = this.pos.x;
            this.last.y = this.pos.y;
            this.vel = vel;
            this.rotationspeed = rotation;
            this.isAlive = isAlive;
            this.activate();
            this.gravity = 500;
            this.accel.x = 0;
            this.accel.y = 0;
            //this.lifetime = 5.0;
        };

        this.update = function () {
            if (this.isAlive) {
                //if (this.lifeTimer.delta() > this.lifetime) {
                //  this.isAlive = false;
                //return true;
                //}
                var gravity_amp = 10;
                this.last.x = this.pos.x;
                this.last.y = this.pos.y;


                this.pos.x += game.system.map.gravity.x * gravity_amp;
                this.pos.y += game.system.map.gravity.y * gravity_amp;

                this.interpolate_diff.x = this.pos.x - this.last.x;
                this.interpolate_diff.y = this.pos.y - this.last.y;

                if (this.pos.x > this.kill_x | this.pos.y > this.kill_y) {
                    this.isAlive = false;
                    return true;
                }
                this.updateAngle();
            }

            return false;

        };

        this.draw = function () {
            var scale = 1;
            this.baseframe.draw(this.last.x + (this.interpolate_diff.x * game.system.interpolationvalue),
                this.last.y + (this.interpolate_diff.y * game.system.interpolationvalue),
                this.spritesheet,
                this.last.angle + (this.interpolate_diff.angle * game.system.interpolationvalue), false, scale);
        };

        this.updateAngle = function () {
            this.last.angle = this.angle;

            this.angle += this.rotationspeed;
            if (this.angle > 360) { this.angle = 0; }

            if (this.last.angle > this.angle) {
                this.interpolate_diff.angle = this.angle + (360 - this.last.angle);
            }
            else {
                this.interpolate_diff.angle = this.angle - this.last.angle;
            }

            return;
        };

        this.activate = function () { 
            this.manager.isActive.push(this);
        };

        this.deactivate = function () {
            this.manager.isActive.splice(this.manager.isActive.indexOf(this), 1);
        };

        this.init(manager);
    };

    game.ParticleManager = ParticleManager; //Assign Object to Game Namespace
    game.Particle = Particle; //Assign Object to Game Namespace

})(window);
